package com.unittec.zk.provider.exam.service;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.aliyun.oss.ServiceException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.unittec.zk.provider.exam.entity.*;
import com.unittec.zk.provider.exam.enums.JoinType;
import com.unittec.zk.provider.exam.enums.PaperState;
import com.unittec.zk.provider.exam.enums.QuType;
import com.unittec.zk.provider.exam.utils.BeanMapper;
import com.unittec.zk.provider.scope.ThreadLocalScope;
import com.unittec.zk.sdk.exam.domain.ExamRepoDTO;
import com.unittec.zk.sdk.exam.domain.PaperQuAnswerExtDTO;
import com.unittec.zk.sdk.exam.domain.PaperQuDTO;
import com.unittec.zk.sdk.exam.domain.PaperQuDetailDTO;
import com.unittec.zk.sdk.exam.enums.ExamState;
import com.unittec.zk.sdk.exam.request.*;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.unittec.zk.provider.exam.mapper.ElPaperMapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

@Service
@Transactional
public class ElPaperService extends ServiceImpl<ElPaperMapper, ElPaper> {

    @Resource
    private ElExamService elExamService;

    @Resource
    private ElExamRepoService elExamRepoService;

    @Resource
    private ElQuService elQuService;

    @Resource
    private SysUserDepartService sysUserDepartService;

    @Resource
    private ElPaperService elPaperService;

    @Resource
    private ElQuAnswerService elQuAnswerService;

    @Resource
    private ElPaperQuService elPaperQuService;

    @Resource
    private ElPaperQuAnswerService elPaperQuAnswerService;

    @Resource
    private ElUserExamService elUserExamService;

    @Resource
    private ElUserBookService elUserBookService;

    @Resource
    private ElExamDepartService elExamDepartService;

    /**
     * 展示的选项，ABC这样
     */
    private static List<String> ABC = Arrays.asList(new String[]{
            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K","L","M","N","O","P","Q","R","S","T","U","V","W","X"
            ,"Y","Z"
    });

    /**
     * 创建试卷
     * @param req201019
     * @return
     */
    public Object createPaper(Req201019 req201019) {
        String examId = req201019.getExamId();
        String userId = ThreadLocalScope.getAuthData().getUser();
        // 查找考试
        ElExam exam = elExamService.getById(examId);

        if(exam == null){
            throw new ServiceException("考试不存在！");
        }

        if(!ExamState.ENABLE.equals(exam.getState())){
            throw new ServiceException("El状态不正确！");
        }

        // 考试题目列表
        List<ElPaperQu> quList = new ArrayList<>();

        // 按题库组卷的
        if(JoinType.REPO_JOIN.equals(exam.getJoinType())){
            //查找规则选定的题库
            quList = this.generateByRepo(examId, exam.getLevel());
        }

        if(CollectionUtils.isEmpty(quList)){
            throw new ServiceException("规则不正确，无对应的考题！");
        }

        //保存试卷内容
        String paperId = this.savePaper(userId, exam, quList);

        return paperId;
    }

    /**
     * 题库组题方式产生题目列表
     * @param examId
     * @return
     */
    private List<ElPaperQu> generateByRepo(String examId, Integer level){

        // 查找规则指定的题库
        List<ExamRepoDTO> list = elExamRepoService.listByExam(examId);

        //最终的题目列表
        List<ElPaperQu> quList = new ArrayList<>();

        //排除ID，避免题目重复
        List<String> excludes = new ArrayList<>();
        excludes.add("none");

        if (!CollectionUtils.isEmpty(list)) {
            for (ExamRepoDTO item : list) {

                // 单选题
                if(item.getRadioCount() > 0){
                    List<ElQu> radioList = elQuService.listByRandom(item.getRepoId(), QuType.RADIO, level, excludes, item.getRadioCount());
                    for (ElQu qu : radioList) {
                        ElPaperQu paperQu = this.processPaperQu(item, qu);
                        quList.add(paperQu);
                        excludes.add(qu.getId());
                    }
                }

                //多选题
                if(item.getMultiCount() > 0) {
                    List<ElQu> multiList = elQuService.listByRandom(item.getRepoId(), QuType.MULTI, level, excludes,
                            item.getMultiCount());
                    for (ElQu qu : multiList) {
                        ElPaperQu paperQu = this.processPaperQu(item, qu);
                        quList.add(paperQu);
                        excludes.add(qu.getId());
                    }
                }

                // 判断题
                if(item.getJudgeCount() > 0) {
                    List<ElQu> judgeList = elQuService.listByRandom(item.getRepoId(), QuType.JUDGE, level, excludes,
                            item.getJudgeCount());
                    for (ElQu qu : judgeList) {
                        ElPaperQu paperQu = this.processPaperQu(item, qu);
                        quList.add(paperQu);
                        excludes.add(qu.getId());
                    }
                }
            }
        }
        return quList;
    }

    /**
     * 填充试题题目信息
     * @param repo
     * @param qu
     * @return
     */
    private ElPaperQu processPaperQu(ExamRepoDTO repo, ElQu qu) {

        //保存试题信息
        ElPaperQu paperQu = new ElPaperQu();
        paperQu.setQuId(qu.getId());
        paperQu.setAnswered((byte) 0);
        paperQu.setIsRight((byte) 0);
        paperQu.setQuType(qu.getQuType());

        if (QuType.RADIO.equals(qu.getQuType())) {
            paperQu.setScore(repo.getRadioScore());
            paperQu.setActualScore(repo.getRadioScore());
        }

        if (QuType.MULTI.equals(qu.getQuType())) {
            paperQu.setScore(repo.getMultiScore());
            paperQu.setActualScore(repo.getMultiScore());
        }

        if (QuType.JUDGE.equals(qu.getQuType())) {
            paperQu.setScore(repo.getJudgeScore());
            paperQu.setActualScore(repo.getJudgeScore());
        }

        return paperQu;
    }

    /**
     * 保存试卷
     * @param userId
     * @param exam
     * @param quList
     * @return
     */
    private String savePaper(String userId, ElExam exam, List<ElPaperQu> quList) {


        // 查找用户
//        LambdaQueryWrapper<El> qw = new LambdaQueryWrapper<>();
//        qw.eq(SysUserDepart::getUserId,userId);
//        SysUserDepart user = sysUserDepartService.getOne(qw);

        //保存试卷基本信息
        ElPaper paper = new ElPaper();
//        paper.setDepartId(user.getDepId());
        paper.setExamId(exam.getId());
        paper.setTitle(exam.getTitle());
        paper.setTotalScore(exam.getTotalScore());
        paper.setTotalTime(exam.getTotalTime());
        paper.setUserScore(0);
        paper.setUserId(userId);
        paper.setCreateTime(new Date());
        paper.setQualifyScore(exam.getQualifyScore());
        paper.setState(PaperState.ING);
        paper.setHasSaq((byte) 0);

        // 截止时间
        Calendar cl = Calendar.getInstance();
        cl.setTimeInMillis(System.currentTimeMillis());
        cl.add(Calendar.MINUTE, exam.getTotalTime());
        paper.setLimitTime(cl.getTime());

        elPaperService.save(paper);

        if (!CollectionUtils.isEmpty(quList)) {
            this.savePaperQu(paper.getId(), quList);
        }

        return paper.getId();
    }


    /**
     * 保存试卷试题列表
     * @param paperId
     * @param quList
     */
    private void savePaperQu(String paperId, List<ElPaperQu> quList){

        List<ElPaperQu> batchQuList = new ArrayList<>();
        List<ElPaperQuAnswer> batchAnswerList = new ArrayList<>();

        int sort = 0;
        for (ElPaperQu item : quList) {

            item.setPaperId(paperId);
            item.setSort(sort);
            item.setId(IdWorker.getIdStr());

            //回答列表
            List<ElQuAnswer> answerList = elQuAnswerService.listAnswerByRandom(item.getQuId());

            if (!CollectionUtils.isEmpty(answerList)) {

                int ii = 0;
                for (ElQuAnswer answer : answerList) {
                    ElPaperQuAnswer paperQuAnswer = new ElPaperQuAnswer();
                    paperQuAnswer.setId(UUID.randomUUID().toString());
                    paperQuAnswer.setPaperId(paperId);
                    paperQuAnswer.setQuId(answer.getQuId());
                    paperQuAnswer.setAnswerId(answer.getId());
                    paperQuAnswer.setChecked((byte) 0);
                    paperQuAnswer.setSort(ii);
                    paperQuAnswer.setAbc(ABC.get(ii));
                    paperQuAnswer.setIsRight(answer.getIsRight());
                    ii++;
                    batchAnswerList.add(paperQuAnswer);
                }
            }

            batchQuList.add(item);
            sort++;
        }

        //添加问题
        elPaperQuService.saveBatch(batchQuList);

        //批量添加问题答案
        elPaperQuAnswerService.saveBatch(batchAnswerList);
    }

    /**
     * 在线考试-试卷详情
     * @param req201020
     * @return
     */
    public Object getPaperDetail(Req201020 req201020) {
        String paperId = req201020.getId();
        // 试题基本信息
        ElPaper paper = elPaperService.getById(paperId);
        Map map = JSON.parseObject(JSON.toJSONString(paper), Map.class);

        // 查找题目列表
        List<PaperQuDTO> list = elPaperQuService.listByPaper(paperId);

        List<PaperQuDTO> radioList = new ArrayList<>();
        List<PaperQuDTO> multiList = new ArrayList<>();
        List<PaperQuDTO> judgeList = new ArrayList<>();
        for(PaperQuDTO item: list){
            if(QuType.RADIO.equals(item.getQuType())){
                radioList.add(item);
            }
            if(QuType.MULTI.equals(item.getQuType())){
                multiList.add(item);
            }
            if(QuType.JUDGE.equals(item.getQuType())){
                judgeList.add(item);
            }
        }
        map.put("radioList",radioList);
        map.put("multiList",multiList);
        map.put("judgeList",judgeList);
        return map;
    }

    /**
     * 在线考试-问题详情
     * @param req201021
     * @return
     */
    public Object getQuDetail(Req201021 req201021) {
        String quId = req201021.getQuId();
        String paperId = req201021.getPaperId();
        // 问题
        ElQu qu = elQuService.getById(quId);

        // 基本信息
        ElPaperQu paperQu = elPaperQuService.findByKey(paperId, quId);
        Map map = JSON.parseObject(JSON.toJSONString(paperQu), Map.class);
        map.put("content",qu.getContent());
        map.put("image",qu.getImage());

        // 答案列表
        List<PaperQuAnswerExtDTO> list = elPaperQuAnswerService.listForExam(paperId, quId);
        map.put("answerList",list);

        return map;
    }

    /**
     * 在线考试-填答案
     * @param req201022
     * @return
     */
    public Object fillAnswer(Req201022 req201022) {
        // 未作答
        if(CollectionUtils.isEmpty(req201022.getAnswers()) && StrUtil.isBlank(req201022.getAnswer())){
            return "没选择答案";
        }

        //查找答案列表
        List<ElPaperQuAnswer> list = elPaperQuAnswerService.listForFill(req201022.getPaperId(), req201022.getQuId());

        //是否正确
        Byte right = 1;

        //更新正确答案
        for (ElPaperQuAnswer item : list) {

            if (req201022.getAnswers().contains(item.getId())) {
                item.setChecked((byte) 1);
            } else {
                item.setChecked((byte) 0);
            }

            //有一个对不上就是错的
            if (item.getIsRight()!=null && item.getIsRight()!=item.getChecked()) {
                right = 0;
            }
            elPaperQuAnswerService.updateById(item);
        }

        //修改为已回答
        ElPaperQu qu = new ElPaperQu();
        qu.setQuId(req201022.getQuId());
        qu.setPaperId(req201022.getPaperId());
        qu.setIsRight(right);
        qu.setAnswer(req201022.getAnswer());
        qu.setAnswered((byte) 1);

        elPaperQuService.updateByKey(qu);
        return "Success";
    }

    /**
     * 交卷操作
     * @param req201023
     * @return
     */
    public Object handleExam(Req201023 req201023) {
        String paperId = req201023.getId();
        //获取试卷信息
        ElPaper paper = elPaperService.getById(paperId);

        //如果不是正常的，抛出异常
        if(!PaperState.ING.equals(paper.getState())){
            throw new ServiceException("试卷状态不正确！");
        }

        // 客观分
        int objScore = elPaperQuService.getBaseMapper().sumObjective(paperId);
        paper.setObjScore(objScore);
        paper.setUserScore(objScore);

        // 主观分，因为要阅卷，所以给0
        paper.setSubjScore(0);

        // 待阅卷
        if(paper.getHasSaq()==1) {
            paper.setState(PaperState.WAIT_OPT);
        }else {

            // 同步保存考试成绩
            elUserExamService.joinResult(paper.getUserId(), paper.getExamId(), objScore, objScore>=paper.getQualifyScore());

            paper.setState(PaperState.FINISHED);
        }

        //计算考试时长
        Calendar cl = Calendar.getInstance();
        cl.setTimeInMillis(System.currentTimeMillis());
        int userTime = (int)((System.currentTimeMillis() - paper.getCreateTime().getTime()) / 1000 / 60);
        if(userTime == 0){
            userTime = 1;
        }
        paper.setUserTime(userTime);

        //更新试卷
        elPaperService.updateById(paper);

        //把打错的问题加入错题本
        List<PaperQuDTO> list = elPaperQuService.listByPaper(paperId);
        for(PaperQuDTO qu: list){
            // 主观题和对的都不加入错题库
            if(qu.getIsRight()==1){
                continue;
            }
            //加入错题本
            elUserBookService.addBook(paper.getExamId(), qu.getQuId());
        }
        return "Success";
    }

    /**
     * 在线考试-考试结果
     * @param req201024
     * @return
     */
    public Object getPaperResult(Req201024 req201024) {
        String paperId = req201024.getId();

        // 试题基本信息
        ElPaper paper = elPaperService.getById(paperId);
        Map map = JSON.parseObject(JSON.toJSONStringWithDateFormat(paper,"yyyy-MM-dd HH:mm:ss"), Map.class);

        List<PaperQuDetailDTO> quList = elPaperQuService.getBaseMapper().listForPaperResult(paperId);
        map.put("quList",quList);

        map.put("userId_dictText",this.baseMapper.getRealNameById(paper.getUserId()));
        return map;
    }
}
